#include "MemEdit.h"

MEMBLOCK *create_memblock(HANDLE hProc, MEMORY_BASIC_INFORMATION *meminfo)
{

	MEMBLOCK *mb = new MEMBLOCK;
	if(mb)
	{
		mb->hProc = hProc;
		mb->addr = (unsigned char*)meminfo->BaseAddress;
		mb->size = meminfo->RegionSize;
		mb->buffer = new unsigned char [meminfo->RegionSize];
		mb->next = NULL;

	}
	return mb;
}


void free_memblock(MEMBLOCK *mb)
{
	if(mb)
	{		
		delete mb->buffer;
	}
	delete mb;
}

void update_memblock(MEMBLOCK *mb, SEARCH_CONDITION cond, unsigned int value)
{
	static unsigned char tempbuf[128*1024];
	unsigned int bytes_left;
	unsigned int total_left;
	SIZE_T bytes_to_read;
	SIZE_T bytes_read;
	unsigned int total_read;

	if(mb->matches > 0)
	{
		bytes_left = mb->size;
		total_read = 0;
	}
	else return;

	while(bytes_left)
	{
		bytes_to_read = (bytes_left > sizeof(tempbuf)) ? sizeof(tempbuf) : bytes_left;
		ReadProcessMemory(mb->hProc, mb->addr + total_read, tempbuf, bytes_to_read, &bytes_read);
		if(bytes_read != bytes_to_read) break;

		switch(cond)
		{
		case C_NONE:
			{
			memset(mb->searchmask + (total_read/8), 0xFF, bytes_read/8);
			mb->matches += bytes_read;
			break;
			}
		default:
			{
				unsigned int offset;
				for(offset = 0;offset < bytes_read; offset += mb->data_size)
				{
					if(IS_IN_SEARCH(mb, (total_read + offset)))
					{
						bool is_match = false;
						unsigned int tmp_val;

						switch(mb->data_size)
						{
							case 1:
								tmp_val = tempbuf[offset];
								break;
							case 2:
								tmp_val = *((unsigned short *)&tempbuf[offset]);
								break;
							case 4:
								tmp_val = *((unsigned int *)&tempbuf[offset]);
								break;
						}
						switch(cond)
						{
							case C_EQUAL:
								is_match = (tmp_val == value);
								break;
							case C_BYTES:
								is_match = (tmp_val == value);
								break;
							default:
								break;
						}
						if(is_match)
							mb->matches++;
						else
							REMOVE_FROM_SEARCH(mb, (total_read + offset));
					}
				}
			}
		}

		memcpy(mb->buffer + total_read, tempbuf, bytes_read);
		bytes_left -= bytes_read;
		total_read += bytes_read;
	}
	mb->size = total_read;
}

void update_scan(MEMBLOCK *mb_list, SEARCH_CONDITION cond, unsigned int value)
{
	MEMBLOCK *mb = mb_list;
	while(mb)
	{
		update_memblock(mb, cond, value);
		mb = mb->next;
	}
}
MEMBLOCK *create_scan(unsigned int pid)
{
	MEMBLOCK *mb_list = NULL;
	MEMORY_BASIC_INFORMATION meminfo;
	unsigned char *addr = 0;

	HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);

	if(hProc)
	{
		while(1)
		{
			if(VirtualQueryEx(hProc, addr, &meminfo, sizeof(meminfo)) == 0)
			{
				break;
			}
			
			if((meminfo.State & MEM_COMMIT) && (meminfo.Protect & WRITABLE))
			{
				MEMBLOCK *mb = create_memblock(hProc, &meminfo);
				if(mb)
				{
					mb->next = mb_list;
					mb_list = mb;
				}
			}
			addr = (unsigned char *)meminfo.BaseAddress + meminfo.RegionSize;
		}
	}
	return mb_list;
}

void free_scan(MEMBLOCK *mb_list)
{
	CloseHandle(mb_list->hProc);
	while(mb_list)
	{
		MEMBLOCK *mb = mb_list;
		mb_list = mb_list->next;

		//delete mb->buffer;
		//delete mb->searchmask;
		free_memblock(mb);
	}

}

void dump_scan_info(MEMBLOCK *mb_list)
{
	MEMBLOCK *mb = mb_list;
	while(mb)
	{
		printf("0x%08x %d\r\n", mb->addr, mb->size);
		//for(int i = 0; i < mb->size; i++) printf("%02x", mb->buffer[i]);
		mb = mb->next;
	}
}
